﻿using System;
using System.Collections.Generic;
using System.Globalization;
using System.IO;
using EnvDTE;
using EnvDTE80;

namespace BuildIncrement {
    /// <summary>
    /// 
    /// </summary>
    public enum SolutionItemType {
        /// <summary>
        /// 
        /// </summary>
        Project,
        /// <summary>
        /// 
        /// </summary>
        Folder
    }

    /// <summary>
    /// 
    /// </summary>
    public class SolutionItem {
        public SolutionItemType ItemType;
        public string Name;

        public Project Project;

        public List<SolutionItem> SubItems;
    }

    /// <summary>
    /// Utility class for global variables
    /// </summary>
    static class Utility {
        /// <summary>
        /// Application object
        /// </summary>
        public static DTE2 applicationObject;

        /// <summary>
        /// Get a global variable from a currently opened solution
        /// </summary>
        /// <param name="varName">Variable name</param>
        /// <param name="defaultVal">Default value</param>
        /// <returns>Variable's value if found, defaultVal otherwise</returns>
        public static string GetGlobalVariable(string varName, string defaultVal) {
            return GetGlobalVariable(applicationObject.Solution.Globals, varName, defaultVal);
        }

        /// <summary>
        /// Get a global variable from a project
        /// </summary>
        /// <param name="project">Project</param>
        /// <param name="varName">Variable name</param>
        /// <param name="defaultVal">Default value</param>
        /// <returns>Variable's value if found, defaultVal otherwise</returns>
        public static string GetGlobalVariable(Project project, string varName, string defaultVal) {
            return GetGlobalVariable(project.Globals, varName, defaultVal);
        }

        /// <summary>
        /// Get a global variable from a array of global variables
        /// </summary>
        /// <param name="globals">Array of global variables</param>
        /// <param name="varName">Variable name</param>
        /// <param name="defaultVal">Default value</param>
        /// <returns>Variable's value if found, defaultVal otherwise</returns>
        private static string GetGlobalVariable(Globals globals, string varName, string defaultVal) {
            object[] names = (object[])globals.VariableNames;

            if (globals.get_VariableExists(varName)) {
                foreach (object name in names) {
                    if (name.ToString() == varName) {
                        return (string)globals[varName];
                    }
                }
            }

            return defaultVal;
        }

        /// <summary>
        /// Save a global variable in the currently opened solution
        /// </summary>
        /// <param name="varName">Variable name</param>
        /// <param name="value">Value to save</param>
        public static void SetGlobalVariable(string varName, string value) {
            SetGlobalVariable(applicationObject.Solution.Globals, varName, value);
        }

        /// <summary>
        /// Save a global variable to a specific project
        /// </summary>
        /// <param name="project">Project</param>
        /// <param name="varName">Variable name</param>
        /// <param name="value">Value to save</param>
        public static void SetGlobalVariable(Project project, string varName, string value) {
            SetGlobalVariable(project.Globals, varName, value);
        }

        /// <summary>
        /// Set a global variable to a array of global variables
        /// </summary>
        /// <param name="globals">Array of global variables</param>
        /// <param name="varName">Variable name</param>
        /// <param name="value">Value to save</param>
        private static void SetGlobalVariable(Globals globals, string varName, string value) {
            globals[varName] = value;
            globals.set_VariablePersists(varName, true);
        }

        /// <summary>
        /// Gets StartDate global variable from a project
        /// </summary>
        /// <param name="project">Project</param>
        /// <returns>StartDate variable's value if variable found, 
        /// project creation date otherwise</returns>
        /// <remarks>If StartDate variable is not found, it is saved
        /// with a value of project creation date</remarks>
        public static DateTime GetProjectDate(Project project) {
            // Get project creation date...
            DateTime creationDate = File.GetCreationTime(project.FullName);
            string savedDate = GetGlobalVariable(project, "StartDate", null);

            DateTime returnValue;

            // StartDate found?
            if (savedDate != null) {
                // Format valid?
                if (DateTime.TryParseExact(savedDate, "yyyyMMdd", CultureInfo.InvariantCulture,
                    DateTimeStyles.None, out returnValue)) {
                    return returnValue;
                }
            }

            // If StartDate not found or the format is not correct,
            // write the variable with project creation date
            SetProjectDate(project, creationDate);

            return creationDate;
        }

        /// <summary>
        /// Sets StartDate global variable to a project
        /// </summary>
        /// <param name="project">Project</param>
        /// <param name="date">Date to set</param>
        public static void SetProjectDate(Project project, DateTime date) {
            SetGlobalVariable(project, "StartDate", date.ToString("yyyyMMdd"));
        }

        public static void GetSolutionItems(ref List<SolutionItem> solutionItems) {
            Projects projects = Connect.applicationObject.Solution.Projects;

            foreach (Project project in projects) {
                string projectPath = project.FullName.Trim();

                SolutionItem si = new SolutionItem();
                si.Name = project.Name;

                // If projectPath is empty, this item is a folder!!
                if (string.IsNullOrEmpty(projectPath)) {
                    si.ItemType = SolutionItemType.Folder;
                    si.SubItems = new List<SolutionItem>();

                    GetProjects(ref si.SubItems, project.ProjectItems);
                }
                else {
                    si.ItemType = SolutionItemType.Project;
                    si.Project = project;
                }

                solutionItems.Add(si);
            }
        }

        private static void GetProjects(ref List<SolutionItem> solutionItems, ProjectItems projectItems) {
            foreach (ProjectItem projectItem in projectItems) {
                Project project = projectItem.SubProject;

                if (project != null) {
                    string projectPath = project.FullName.Trim();

                    SolutionItem si = new SolutionItem();
                    si.Name = project.Name;

                    // If projectPath is empty, this item is a folder!!
                    if (string.IsNullOrEmpty(projectPath)) {
                        si.ItemType = SolutionItemType.Folder;
                        si.SubItems = new List<SolutionItem>();

                        GetProjects(ref si.SubItems, project.ProjectItems);
                    }
                    else {
                        si.ItemType = SolutionItemType.Project;
                        si.Project = project;
                    }

                    solutionItems.Add(si);
                }
            }
        }
    }
}
